home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume10 / stat < prev    next >
Encoding:
Text File  |  1990-02-26  |  28.5 KB  |  1,149 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v10i082: Stat(1)
  3. From: dds@cc.ic.ac.uk (Diomidis Spinellis)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 10, Issue 82
  7. Submitted-by: dds@cc.ic.ac.uk (Diomidis Spinellis)
  8. Archive-name: stat
  9.  
  10. Stat is a program that brings all the power of the stat(2) system call
  11. to the shell programer.  It can be used to print various
  12. characteristics of a file such as its size, permissions, dates, type
  13. etc. in a variety of user specified formats.  The output can be easily
  14. manipulated with tools such as awk, sed and sort to provide complex
  15. file selection and printing mechanisms.  Obvious applications are
  16. novice-user-friendly versions of ls(1) and getting the mode of a file
  17. in a way that can be later used by chmod(1).  It has been tested under 
  18. 4.3 BSD, AIX, HP/UX, SunOS, and Ultrix.
  19.  
  20. #! /bin/sh
  21. # This is a shell archive, meaning:
  22. # 1. Remove everything above the #! /bin/sh line.
  23. # 2. Save the resulting text in a file.
  24. # 3. Execute the file with /bin/sh (not csh) to create the files:
  25. #    README
  26. #    Makefile
  27. #    stat.1
  28. #    stat.c
  29. # This archive created: Wed Feb 21 21:21:02 1990
  30. export PATH; PATH=/bin:$PATH
  31. echo shar: extracting "'README'" '(1374 characters)'
  32. if test -f 'README'
  33. then
  34.     echo shar: will not over-write existing file "'README'"
  35. else
  36. sed 's/^X//' << \SHAR_EOF > 'README'
  37. X
  38. XStat is a program that brings all the power of the stat(2) system call
  39. Xto the shell programer.  It can be used to print various
  40. Xcharacteristics of a file such as its size, permissions, dates, type
  41. Xetc. in a variety of user specified formats.  The output can be easily
  42. Xmanipulated with tools such as awk, sed and sort to provide complex
  43. Xfile selection and printing mechanisms.  Obvious applications are
  44. Xnovice-user-friendly versions of ls(1) and getting the mode of a file
  45. Xin a way that can be later used by chmod(1).  It has been tested under 
  46. X4.3 BSD, AIX, HP/UX, SunOS, and Ultrix.
  47. X
  48. XThe output format is specified at three different levels in a
  49. Xprintf(3S) like way.  A global output format string specifies the
  50. Xitems which are printed.  The way the different time values are printed
  51. Xis specified by other format strings.  Finaly the way each individual
  52. Xfield is printed (number base, justification, padding) can be specified
  53. Xusing the normal printf specifications.
  54. X
  55. XComments and additions can be sent to the author:
  56. X
  57. X    Diomidis Spinellis
  58. X    Myrsinis 1
  59. X    GR-145 62 Kifissia
  60. X    GREECE
  61. X
  62. X--
  63. XDiomidis Spinellis                  Internet:                 dds@cc.ic.ac.uk
  64. XDepartment of Computing             UUCP:                    ...!ukc!iccc!dds
  65. XImperial College                    JANET:                    dds@uk.ac.ic.cc
  66. XLondon SW7 2BZ                      #include "/dev/tty"
  67. SHAR_EOF
  68. if test 1374 -ne "`wc -c < 'README'`"
  69. then
  70.     echo shar: error transmitting "'README'" '(should have been 1374 characters)'
  71. fi
  72. fi # end of overwriting check
  73. echo shar: extracting "'Makefile'" '(464 characters)'
  74. if test -f 'Makefile'
  75. then
  76.     echo shar: will not over-write existing file "'Makefile'"
  77. else
  78. sed 's/^X//' << \SHAR_EOF > 'Makefile'
  79. X#
  80. X# Makefile for stat
  81. X#
  82. X
  83. X# Binary destination
  84. Xbin = /usr/local/bin
  85. X
  86. X# Unformated manual page destination
  87. Xmansrc = /usr/local/man/man1
  88. X
  89. XCC = cc
  90. XCFLAGS = -O
  91. XLINTFLAGS = -chabx
  92. X
  93. Xall: stat
  94. X
  95. Xstat: stat.c
  96. X    $(CC) $(CFLAGS) stat.c -o stat
  97. X
  98. Xinstall: stat stat.1
  99. X    install stat $(bin)
  100. X    install stat.1 $(mansrc)
  101. X
  102. Xclean:
  103. X    rm -f stat.o 
  104. X
  105. Xclobber:
  106. X    rm -f stat.o stat core
  107. X
  108. Xlint:
  109. X    lint $(LINTFLAGS) stat.c >stat.lint
  110. X
  111. Xshar:
  112. X    shar -cv -p X README Makefile stat.1 stat.c >stat.shar
  113. SHAR_EOF
  114. if test 464 -ne "`wc -c < 'Makefile'`"
  115. then
  116.     echo shar: error transmitting "'Makefile'" '(should have been 464 characters)'
  117. fi
  118. fi # end of overwriting check
  119. echo shar: extracting "'stat.1'" '(8549 characters)'
  120. if test -f 'stat.1'
  121. then
  122.     echo shar: will not over-write existing file "'stat.1'"
  123. else
  124. sed 's/^X//' << \SHAR_EOF > 'stat.1'
  125. X.\"
  126. X.\" (C) Copyright 1989 Diomidis D. Spinellis.  All rights reserved.
  127. X.\"
  128. X.\" Redistribution and use in source and formated forms are permitted
  129. X.\" provided that the above copyright notice and this paragraph are
  130. X.\" duplicated in all such forms and that any documentation,
  131. X.\" advertising materials, and other materials related to such
  132. X.\" distribution and use acknowledge that the software was developed
  133. X.\" by Diomidis D. Spinellis.
  134. X.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  135. X.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  136. X.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  137. X.\"
  138. X.TH STAT 1 
  139. X.SH NAME
  140. Xstat \- print file status information
  141. X.SH SYNOPSIS
  142. X.B stat
  143. X[
  144. X.BI \-g
  145. X]
  146. X[
  147. X.BI \-l
  148. X]
  149. X[
  150. X.BI \-e
  151. X]
  152. X[
  153. X.BI \-f " format"
  154. X]
  155. X[
  156. X.BI \-t " time_format"
  157. X]
  158. X[
  159. X.BI \-m " time_format"
  160. X]
  161. X[
  162. X.BI \-a " time_format"
  163. X]
  164. X[
  165. X.BI \-c " time_format"
  166. X]
  167. X[
  168. X.BI \-q " mode_names"
  169. X]
  170. X[
  171. X.BI \-y " type_names"
  172. X]
  173. Xfile ...
  174. X.SH DESCRIPTION
  175. X.I Stat
  176. Xprints status information for each of the files specified.  If a
  177. Xfile name is `\-', then status information about the standard input
  178. Xis displayed.
  179. X.PP
  180. XThe output can be specified by means of
  181. X.I printf
  182. Xlike format specifications.  If no format specifications are given, then
  183. X.I ``ls -l''
  184. Xlike output is produced.  
  185. X.SH OPTIONS
  186. X.TP
  187. X.B \-g
  188. XList time fields in UTC (GMT) instead of local time.
  189. X.TP
  190. X.B \-l
  191. XFor symbolic links list the status of the the file it points to instead of
  192. Xthe status of the link (i.e. follow symbolic links).
  193. X.TP
  194. X.B \-e
  195. XExit immediately with an error when stat can not be performed on a file.  If 
  196. Xthis
  197. Xflag is not given then error messages are printed, but the program continues
  198. Xto go through the list of files.
  199. X.TP
  200. X.BI \-f " output format"
  201. XSpecify the output format.
  202. X.TP
  203. X.BI \-a " time format"
  204. XSpecify the output format for the file access time field.
  205. X.TP
  206. X.BI \-m " time format"
  207. XSpecify the output format for the file modification time field.
  208. X.TP
  209. X.BI \-c " time format"
  210. XSpecify the output format for the file status change time field.
  211. X.TP
  212. X.BI \-t " time format"
  213. XSpecify the output format for the current time field.
  214. X.TP
  215. X.BI \-q " mode names"
  216. XSpecify the English description of the file mode giving a list of 24 strings.
  217. XThe strings are separated by an arbitrary character and the list should start
  218. Xand end with that character.  
  219. XThe first three strings 
  220. Xdescribe the set user id, set group id and sticky modes.  
  221. XAfter that, nine strings, the descriptions for read 
  222. Xpermission, write permission and execute permission, first for the owner,
  223. Xthen for the group and then for others must be given.
  224. XAnother set
  225. Xof 12 strings must follow describing the semantics of the above in
  226. Xthe case of directories.
  227. X.TP
  228. X.BI \-y " type names"
  229. XSpecify the English description of the file type giving a list of seven strings.
  230. XThe list is given as in the
  231. X.I -q
  232. Xoption and the strings are the descriptions to be used for directories,
  233. Xblock special files, character special files, symbolic links, named pipes, 
  234. Xsockets and regular files.  All types must be given, even if not supported
  235. Xon a system.
  236. X.PP
  237. XFive format specifications can be given: one for
  238. Xthe whole output and four for the output format of different time values.  
  239. XThe format specification
  240. Xis a string.  All characters in the format specification are printed except
  241. Xfor characters following a `%' sign.  If the first character after a `%' sign
  242. Xis an open bracket `(' then the characters up to the matching closing bracket
  243. Xare taken as a
  244. X.I printf
  245. Xformat specification that will be used to print the item specified.
  246. XA `%' sign in the printf format specification is not needed.
  247. XNote that some systems may not support some of the options.
  248. X.PP
  249. XCharacters following a `%' sign are
  250. Xconverted in the global output specification as follows:
  251. X.RS
  252. X.PD 0
  253. X.TP 5
  254. X.B v
  255. Xdevice the file resides on in decimal
  256. X.TP 5
  257. X.B i
  258. Xthe file's inode number in decimal
  259. X.TP 5
  260. X.B p
  261. Xthe file's protection in octal
  262. X.TP 5
  263. X.B P
  264. Xthe file's protection in an
  265. X.I ls -l
  266. Xlike fashion
  267. X.TP 5
  268. X.B q
  269. Xthe file's protection as a series of nine 0 or 1 digits.  The default format
  270. Xspecification for printf is `%s' and applies to each individual digit
  271. X.TP 5
  272. X.B Q
  273. Xthe file's protection using an English description.  The description can be
  274. Xoptionaly specified using the
  275. X.I .q
  276. Xoption.  If the file is a symbolic link and the
  277. X.I -l
  278. Xoption has not been given, nothing is printed
  279. X.TP 5
  280. X.B l
  281. Xthe number of links the file has in decimal
  282. X.TP 5
  283. X.B u
  284. Xthe user id of the owner of the file in decimal
  285. X.TP 5
  286. X.B U
  287. Xthe user id of the owner of the file as a string
  288. X.TP 5
  289. X.B g
  290. Xthe group id of the owner of the file in decimal
  291. X.TP 5
  292. X.B G
  293. Xthe group id of the owner of the file as a string
  294. X.TP 5
  295. X.B r
  296. Xthe device identifier (only for special files)
  297. X.TP 5
  298. X.B s
  299. Xtotal byte size of the file in decimal 
  300. X.TP 5
  301. X.B a
  302. Xlast access time of file in seconds since 1970
  303. X.TP 5
  304. X.B m
  305. Xlast modification time of file in seconds since 1970
  306. X.TP 5
  307. X.B c
  308. Xlast status change time of file in seconds since 1970
  309. X.TP 5
  310. X.B t
  311. Xcurrent time in seconds since 1970
  312. X.TP 5
  313. X.B A
  314. Xlast access time of file as the string specified by the access time format
  315. X.TP 5
  316. X.B M
  317. Xlast modification time of file as the string specified by the modification time 
  318. Xformat
  319. X.TP 5
  320. X.B C
  321. Xlast status change time of file as the string specified by the change 
  322. Xtime format
  323. X.TP 5
  324. X.B T
  325. Xcurrent time as the string specified by the current time format
  326. X.TP 5
  327. X.B z
  328. Xpreferred blocksize for file I/O
  329. X.TP 5
  330. X.B b
  331. Xactual number of blocks allocated
  332. X.TP 5
  333. X.B n
  334. Xthe name of the file
  335. X.TP 5
  336. X.B f
  337. Xa `/' for directories, `@' for symbolic links, `=' for AF_UNIX domain sockets
  338. Xand `*' for executable files.  If the name of a symbolic link or an arrow is
  339. Xprinted as a result of %L or %- then the `@' is not printed.
  340. X.TP 5
  341. X.B F
  342. XThe type of the file is printed as one of the symbols S_IFIDR, S_IFBLK,
  343. XS_IFCHAR, S_IFLNK, S_IFIFO, S_IFSOCK, S_IFREG for directories, block
  344. Xspecial files, character special files, symbolic links, FIFO special files,
  345. XAF_UNIX domain sockets and regular files.
  346. X.TP 5
  347. X.B Y
  348. XThe type of the file using an English description, optionaly specified using
  349. Xthe
  350. X.I -y
  351. Xoption
  352. X.TP 5
  353. X.B L
  354. Xif the file is a symbolic link, the contents of the link
  355. X.TP 5
  356. X.B -
  357. Xif the file is a symbolic link, the character sequence ` -> '
  358. X.PD
  359. X.RE
  360. X.PP
  361. XThe default time format specification produces
  362. X.I `ls -l'
  363. Xlike time output.
  364. XCharacters following a `%' sign are
  365. Xconverted in the time output specification as follows:
  366. X.RS
  367. X.PD 0
  368. X.TP 5
  369. X.B m
  370. Xthe month number in decimal (1-12)
  371. X.TP 5
  372. X.B d
  373. Xthe day of month number in decimal (1-31)
  374. X.TP 5
  375. X.B y
  376. Xthe year in decimal (1900-...)
  377. X.TP 5
  378. X.B Y
  379. Xthe year in decimal printed only if the time is more that half a year older
  380. Xthan the current time.
  381. X.TP 5
  382. X.B H
  383. Xthe hour of the day in decimal (0-23)
  384. X.TP 5
  385. X.B M
  386. Xminutes in decimal (0-59)
  387. X.TP 5
  388. X.B S
  389. Xseconds in decimal (0-59)
  390. X.TP 5
  391. X.B T
  392. Xhours and minutes as 00:00 printed only if time is less than half a
  393. Xyear older than the current time.  (A note for pedants: If the time
  394. Xis exactly equal to the current time minus half a year than hours and
  395. Xminutes are printed.)
  396. X.TP 5
  397. X.B j
  398. Xthe day of the year in decimal (0-365)
  399. X.TP 5
  400. X.B w
  401. Xthe day of the week in decimal (Sunday is 0)
  402. X.TP 5
  403. X.B a
  404. Xthe three letter abbreviation of the day of the week
  405. X.TP 5
  406. X.B h
  407. Xthe three letter abbreviation of the month
  408. X.TP 5
  409. X.B z
  410. Xthe offset of the time from UTC (GMT) in seconds
  411. X.TP 5
  412. X.B Z
  413. Xabbreviation of the timezone name
  414. X.TP 5
  415. X.B D
  416. Xthe letters DST if daylight savings time is in effect
  417. X.TP 5
  418. X.B t
  419. XThe time in the form mmddhhmmyy.  This form can be used as an argument
  420. Xof the System V touch command.
  421. X.PD
  422. X.RE
  423. X.PP
  424. X.SH EXAMPLES
  425. X.PP
  426. XList all files in a directory in a
  427. X.I `ls -F'
  428. Xlike fashion (the default time format is `%h %(2d)d %T%(5d)Y'):
  429. X.nf
  430. X    stat -f '%P%(3d)l %(-8s)U %(8ld)s %M %n%-%L%F' *
  431. X.fi
  432. X.PP
  433. XMake depend in a makefile without modifying the permissions of Makefile
  434. X(Makefile can be read only from a version control system).
  435. X.nf
  436. X    PERMS=`stat -f %p Makefile` ;\\
  437. X    chmod 600 Makefile ;\\
  438. X    mkdep $(FILES) ;\\
  439. X    chmod $$PERMS Makefile
  440. X.fi
  441. X.PP
  442. XAn extremely verbose version of ls:
  443. X.nf
  444. X#!/bin/sh
  445. XT='%a %d %h %y %H:%M:%S'
  446. Xstat -a "$T" -c "$T" -m "$T" -f '
  447. XFile:        %n
  448. XType:        %Y
  449. XDevice:        %v(0x%(x)v)
  450. XInode:        %i(0x%(x)i)
  451. XPotection:    %Q
  452. XUser:        %U(%u)
  453. XGroup:        %G(%g)
  454. XFile size:    %s byte(s) %b block(s)
  455. XLast access:    %A
  456. XLast change:    %M
  457. XStatus change:    %C
  458. X ' -y '
  459. XDirectory
  460. XBlock device
  461. XCharacter device
  462. XSymbolic link
  463. XNamed pipe
  464. XSocket
  465. XNormal file
  466. X ' $*
  467. X.fi
  468. X
  469. X.SH AUTHOR
  470. X(C) Copyright 1989 Diomidis D. Spinellis (dds@cc.ic.ac.uk).  All rights reserved.
  471. X.SH SEE ALSO
  472. Xls(1), find(1), printf(3S)
  473. X.SH BUGS
  474. X.PP
  475. XNot quite as many options as ls.
  476. SHAR_EOF
  477. if test 8549 -ne "`wc -c < 'stat.1'`"
  478. then
  479.     echo shar: error transmitting "'stat.1'" '(should have been 8549 characters)'
  480. fi
  481. fi # end of overwriting check
  482. echo shar: extracting "'stat.c'" '(14832 characters)'
  483. if test -f 'stat.c'
  484. then
  485.     echo shar: will not over-write existing file "'stat.c'"
  486. else
  487. sed 's/^X//' << \SHAR_EOF > 'stat.c'
  488. X/*
  489. X * stat - List the status information of a list of files
  490. X *
  491. X * (C) Copyright 1989 Diomidis D. Spinellis.  All rights reserved.
  492. X *
  493. X * Redistribution and use in source and binary forms are permitted
  494. X * provided that the above copyright notice and this paragraph are
  495. X * duplicated in all such forms and that any documentation,
  496. X * advertising materials, and other materials related to such
  497. X * distribution and use acknowledge that the software was developed
  498. X * by Diomidis D. Spinellis.
  499. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  500. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  501. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  502. X *
  503. X * $Header: stat.c,v 1.9 89/11/03 22:53:12 dds Rel $
  504. X *
  505. X */
  506. X
  507. X#include <stdio.h>
  508. X#include <string.h>
  509. X#include <varargs.h>
  510. X#include <pwd.h>
  511. X#include <grp.h>
  512. X#include <sys/types.h>
  513. X#include <sys/stat.h>
  514. X#include <sys/time.h>
  515. X#include <sys/param.h>
  516. X
  517. X#define    STREQ(a, b)    (*(a) == *(b) && strcmp((a), (b)) == 0)
  518. X
  519. X#ifndef lint
  520. Xstatic char RCSid[] = "$Header: stat.c,v 1.9 89/11/03 22:53:12 dds Rel $";
  521. X#endif
  522. X
  523. Xint debug = 0;
  524. Xint lflag = 0;                    /* Follow links */
  525. Xint gflag = 0;                    /* Use GMT */
  526. Xint eflag = 0;                    /* Exit on error */
  527. Xchar *progname;                    /* Base name of the program */
  528. X/* Output format string */
  529. Xchar *format = "%P%(3d)l %(-8s)U %(8ld)s %M %n%-%L";
  530. Xchar *ttformat = "%h %(2d)d %T%(5d)Y";        /* Current time format */
  531. Xchar *tcformat = "%h %(2d)d %T%(5d)Y";        /* Creation time format */
  532. Xchar *taformat = "%h %(2d)d %T%(5d)Y";        /* Access time format */
  533. Xchar *tmformat = "%h %(2d)d %T%(5d)Y";        /* Modification time format */
  534. Xchar *typename[];                /* File type english names */
  535. Xchar *modename[];                /* File mode english names */
  536. Xstruct tm currtime;                /* Current time structure */
  537. Xlong currclock, halfyearago;            /* ... in seconds */
  538. X
  539. Xextern void error(), exit();
  540. Xextern struct tm *localtime(), *gmtime();
  541. X
  542. Xstatic void parsenames();
  543. X
  544. X/*
  545. X * main - parse arguments and handle options
  546. X */
  547. Xmain(argc, argv)
  548. X    int argc;
  549. X    char *argv[];
  550. X{
  551. X    int c;
  552. X    int errflg = 0;
  553. X    extern int optind;
  554. X    extern char *optarg;
  555. X    extern char *mkprogname();
  556. X    void process();
  557. X    struct timeval time;
  558. X    struct timezone zone;
  559. X
  560. X    progname = mkprogname(argv[0]);
  561. X
  562. X    while ((c = getopt(argc, argv, "dglf:t:a:m:c:q:y:")) != EOF)
  563. X        switch (c) {
  564. X#ifndef NDEBUG
  565. X        case 'd':    /* Debugging. */
  566. X            debug++;
  567. X            break;
  568. X#endif
  569. X        case 'e':
  570. X            eflag++;
  571. X            break;
  572. X        case 'g':
  573. X            gflag++;
  574. X            break;
  575. X        case 'l':
  576. X            lflag++;
  577. X            break;
  578. X        case 'c':    /* Format for current time specification */
  579. X            tcformat = optarg;
  580. X            break;
  581. X        case 'a':    /* Format for current time specification */
  582. X            taformat = optarg;
  583. X            break;
  584. X        case 'm':    /* Format for current time specification */
  585. X            tmformat = optarg;
  586. X            break;
  587. X        case 't':    /* Format for current time specification */
  588. X            ttformat = optarg;
  589. X            break;
  590. X        case 'f':    /* Format specification */
  591. X            format = optarg;
  592. X            break;
  593. X        case 'q':    /* Names for english file mode descriptions */
  594. X            parsenames(optarg, modename, 24, "mode");
  595. X            break;
  596. X        case 'y':    /* Names for file type descriptions */
  597. X            parsenames(optarg, typename, 7, "type");
  598. X            break;
  599. X        case '?':
  600. X        default:
  601. X            errflg++;
  602. X            break;
  603. X        }
  604. X    if (errflg || optind >= argc) {
  605. X        fprintf(stderr, "usage: %s [-f format] [-t date_format]file ...\n", progname);
  606. X        exit(2);
  607. X    }
  608. X
  609. X    gettimeofday(&time, &zone);
  610. X    currclock = time.tv_sec;
  611. X    halfyearago = currclock - 365L * 24L * 60L * 60L / 2L;
  612. X    if (gflag)
  613. X        currtime = *gmtime(&time.tv_sec);
  614. X    else
  615. X        currtime = *localtime(&time.tv_sec);
  616. X    for (; optind < argc; optind++)
  617. X        process(argv[optind]);
  618. X    exit(0);
  619. X}
  620. X
  621. X/*
  622. X * List the mode of a file a la ls
  623. X */
  624. X#ifdef __GCC__
  625. Xinline
  626. X#endif
  627. Xstatic void
  628. Xlsmode(mode)
  629. X    unsigned short mode;
  630. X{
  631. X    if ((mode & S_IFMT) == S_IFDIR)
  632. X        putchar('d');
  633. X    else if ((mode & S_IFMT) == S_IFBLK)
  634. X        putchar('b');
  635. X    else if ((mode & S_IFMT) == S_IFCHR)
  636. X        putchar('c');
  637. X#ifdef S_IFLNK
  638. X    else if ((mode & S_IFMT) == S_IFLNK)
  639. X        putchar('l');
  640. X#endif
  641. X#ifdef S_IFIFO
  642. X    else if ((mode & S_IFMT) == S_IFIFO)
  643. X        putchar('p');
  644. X#endif
  645. X#ifdef S_IFSOCK
  646. X    else if ((mode & S_IFMT) == S_IFSOCK)
  647. X        putchar('s');
  648. X#endif
  649. X    else
  650. X        putchar('-');
  651. X    putchar((mode & (S_IREAD >> 0)) ? 'r' : '-');
  652. X    putchar((mode & (S_IWRITE >> 0)) ? 'w' : '-');
  653. X    if (mode & S_ISUID)
  654. X        putchar((mode & (S_IEXEC >> 0)) ? 's' : 'S');
  655. X    else
  656. X        putchar((mode & (S_IEXEC >> 0)) ? 'x' : '-');
  657. X    putchar((mode & (S_IREAD >> 3)) ? 'r' : '-');
  658. X    putchar((mode & (S_IWRITE >> 3)) ? 'w' : '-');
  659. X    if (mode & S_ISGID)
  660. X        putchar((mode & (S_IEXEC >> 3)) ? 's' : 'S');
  661. X    else
  662. X        putchar((mode & (S_IEXEC >> 3)) ? 'x' : '-');
  663. X    putchar((mode & (S_IREAD >> 6)) ? 'r' : '-');
  664. X    putchar((mode & (S_IWRITE >> 6)) ? 'w' : '-');
  665. X    if (mode & S_ISVTX)
  666. X        putchar((mode & (S_IEXEC >> 3)) ? 't' : 'T');
  667. X    else
  668. X        putchar((mode & (S_IEXEC >> 3)) ? 'x' : '-');
  669. X}
  670. X
  671. X#define optform(x) (form[1]?form:(x))
  672. Xstatic char form[512] = "%";
  673. X
  674. X/*
  675. X * Print time using the time format
  676. X */
  677. Xstatic
  678. Xtimef(clock, format)
  679. X    long clock;
  680. X    char *format;
  681. X{
  682. X    struct tm *t;
  683. X    char c, *p, *fp;
  684. X    static char *weekday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  685. X    static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  686. X
  687. X    if (gflag)
  688. X        t = gmtime(&clock);
  689. X    else
  690. X        t = localtime(&clock);
  691. X    for (p = format; *p; p++) {
  692. X        c = *p;
  693. X        if (c != '%')
  694. X            putchar(c);
  695. X        else {
  696. X            fp = form + 1;
  697. X            p++;
  698. X            if (*p == '(') {
  699. X                p++;
  700. X                while (*p && *p != ')')
  701. X                    *fp++ = *p++;
  702. X                if (*p)
  703. X                    p++;
  704. X            }
  705. X            *fp = 0;
  706. X            switch (*p) {
  707. X            case 'm':
  708. X                printf(optform("%d"), t->tm_mon + 1);
  709. X                break;
  710. X            case 'd':
  711. X                printf(optform("%d"), t->tm_mday);
  712. X                break;
  713. X            case 'y':
  714. X                printf(optform("%d"), t->tm_year+1900);
  715. X                break;
  716. X            case 'Y':
  717. X                if (clock < halfyearago)
  718. X                    printf(optform("%d"), t->tm_year+1900);
  719. X                break;
  720. X            case 'H':
  721. X                printf(optform("%d"), t->tm_hour);
  722. X                break;
  723. X            case 'M':
  724. X                printf(optform("%d"), t->tm_min);
  725. X                break;
  726. X            case 'T':
  727. X                if (clock >= halfyearago)
  728. X                    printf("%02d:%02d", t->tm_hour, t->tm_min);
  729. X                break;
  730. X            case 'S':
  731. X                printf(optform("%d"), t->tm_sec);
  732. X                break;
  733. X            case 'j':
  734. X                printf(optform("%d"), t->tm_yday);
  735. X                break;
  736. X            case 'w':
  737. X                printf(optform("%d"), t->tm_wday);
  738. X                break;
  739. X            case 'a':
  740. X                printf(optform("%s"), weekday[t->tm_wday]);
  741. X                break;
  742. X            case 'h':
  743. X                printf(optform("%s"), month[t->tm_mon]);
  744. X                break;
  745. X#ifdef sun
  746. X            case 'z':
  747. X                printf(optform("%s"), t->tm_gmtoff);
  748. X                break;
  749. X            case 'Z':
  750. X                printf(optform("%s"), t->tm_zone);
  751. X                break;
  752. X#endif
  753. X            case 'D':
  754. X                printf(optform("%s"), t->tm_isdst ? "DST" : "");
  755. X                break;
  756. X            case 't':
  757. X                printf("%02d%02d%02d%02d%02d", t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_year);
  758. X                break;
  759. X            default :
  760. X                putchar(*p);
  761. X                break;
  762. X            }
  763. X        }
  764. X    }
  765. X}
  766. X
  767. X/*
  768. X * process - process input file
  769. X */
  770. Xstatic void
  771. Xprocess(inname)
  772. X    char *inname;
  773. X{
  774. X    struct stat statbuf;
  775. X    struct group *grp, *getgrgid();
  776. X    struct passwd *pwd, *getpwuid();
  777. X    int uid = -10, gid = -10;            /* Cached */
  778. X    char *pw_name, *gr_name;
  779. X    char *p, c, *fp, *ctime();
  780. X    int i, j;
  781. X    int Lprinted = 0;
  782. X
  783. X    if (STREQ(inname, "-")) {
  784. X        if (fstat(0, &statbuf) < 0) {
  785. X            error("can't fstat `%s'", inname);
  786. X            return;
  787. X        }
  788. X    } else {
  789. X        if (lflag) {
  790. X            if (stat(inname, &statbuf) < 0) {
  791. X                error("can't stat `%s'", inname);
  792. X                return;
  793. X            }
  794. X        } else {
  795. X            if (lstat(inname, &statbuf) < 0) {
  796. X                error("can't lstat `%s'", inname);
  797. X                return;
  798. X            }
  799. X        }
  800. X    }
  801. X
  802. X    for (p = format; *p; p++) {
  803. X        c = *p;
  804. X        if (c != '%')
  805. X            putchar(c);
  806. X        else {
  807. X            fp = form + 1;
  808. X            p++;
  809. X            if (*p == '(') {
  810. X                p++;
  811. X                while (*p && *p != ')')
  812. X                    *fp++ = *p++;
  813. X                if (*p)
  814. X                    p++;
  815. X            }
  816. X            *fp = 0;
  817. X            switch (*p) {
  818. X            case 'v':
  819. X                printf(optform("%d"), statbuf.st_dev);
  820. X                break;
  821. X            case 'i':
  822. X                printf(optform("%lu"), statbuf.st_ino);
  823. X                break;
  824. X            case 'p':
  825. X                printf(optform("%o"), statbuf.st_mode);
  826. X                break;
  827. X            case 'P':
  828. X                lsmode(statbuf.st_mode);
  829. X                break;
  830. X            case 'l':
  831. X                printf(optform("%d"), statbuf.st_nlink);
  832. X                break;
  833. X            case 'u':
  834. X                printf(optform("%d"), statbuf.st_uid);
  835. X                break;
  836. X            case 'g':
  837. X                printf(optform("%d"), statbuf.st_gid);
  838. X                break;
  839. X            case 'U':
  840. X                if (uid != statbuf.st_uid) {
  841. X                    if (pwd = getpwuid(statbuf.st_uid))
  842. X                        pw_name = pwd->pw_name;
  843. X                    else
  844. X                        pw_name = "[UNKOWN]";
  845. X                }
  846. X                printf(optform("%s"), pw_name);
  847. X                break;
  848. X            case 'G':
  849. X                if (gid != statbuf.st_gid) {
  850. X                    if (grp = getgrgid(statbuf.st_gid))
  851. X                        gr_name = grp->gr_name;
  852. X                    else
  853. X                        gr_name = "[UNKOWN]";
  854. X                }
  855. X                printf(optform("%s"), gr_name);
  856. X                break;
  857. X            case 'r':
  858. X                printf(optform("%d"), statbuf.st_rdev);
  859. X                break;
  860. X            case 's':
  861. X                printf(optform("%ld"), statbuf.st_size);
  862. X                break;
  863. X            case 'a':
  864. X                printf(optform("%ld"), statbuf.st_atime);
  865. X                break;
  866. X            case 'm':
  867. X                printf(optform("%ld"), statbuf.st_mtime);
  868. X                break;
  869. X            case 'c':
  870. X                printf(optform("%ld"), statbuf.st_ctime);
  871. X                break;
  872. X            case 't':
  873. X                printf(optform("%ld"), currclock);
  874. X                break;
  875. X            case 'A':
  876. X                timef(statbuf.st_atime, taformat);
  877. X                break;
  878. X            case 'M':
  879. X                timef(statbuf.st_mtime, tmformat);
  880. X                break;
  881. X            case 'C':
  882. X                timef(statbuf.st_ctime, tcformat);
  883. X                break;
  884. X            case 'T':
  885. X                timef(currclock, ttformat);
  886. X                break;
  887. X#ifndef AIX
  888. X            case 'z':
  889. X                printf(optform("%ld"), statbuf.st_blksize);
  890. X                break;
  891. X            case 'b':
  892. X                printf(optform("%ld"), statbuf.st_blocks);
  893. X                break;
  894. X#endif
  895. X            case 'n':
  896. X                printf(optform("%s"), inname);
  897. X                break;
  898. X            case 'f':
  899. X#ifdef S_IFLNK
  900. X                if ((statbuf.st_mode & S_IFMT) == S_IFLNK && Lprinted)
  901. X                    break;
  902. X#endif
  903. X                if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
  904. X                    putchar('/');
  905. X#ifdef S_IFLNK
  906. X                else if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
  907. X                    putchar('@');
  908. X#endif
  909. X#ifdef S_IFSOCK
  910. X                else if ((statbuf.st_mode & S_IFMT) == S_IFSOCK)
  911. X                    putchar('=');
  912. X#endif
  913. X                else if (statbuf.st_mode & (S_IEXEC | (S_IEXEC >> 3) | (S_IEXEC >> 6)))
  914. X                    putchar('*');
  915. X                else
  916. X                    putchar(' ');
  917. X                break;
  918. X            case 'F':
  919. X                if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
  920. X                    printf(optform("%s"), "S_IFDIR");
  921. X                else if ((statbuf.st_mode & S_IFMT) == S_IFBLK)
  922. X                    printf(optform("%s"), "S_IFBLK");
  923. X                else if ((statbuf.st_mode & S_IFMT) == S_IFCHR)
  924. X                    printf(optform("%s"), "S_IFCHR");
  925. X#ifdef S_IFLNK
  926. X                else if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
  927. X                    printf(optform("%s"), "S_IFLNK");
  928. X#endif
  929. X#ifdef S_IFIFO
  930. X                else if ((statbuf.st_mode & S_IFMT) == S_IFIFO)
  931. X                    printf(optform("%s"), "S_IFIFO");
  932. X#endif
  933. X#ifdef S_IFSOCK
  934. X                else if ((statbuf.st_mode & S_IFMT) == S_IFSOCK)
  935. X                    printf(optform("%s"), "S_IFSOCK");
  936. X#endif
  937. X                else if ((statbuf.st_mode & S_IFMT) == S_IFREG)
  938. X                    printf(optform("%s"), "S_IFREG");
  939. X                else
  940. X                    printf(optform("%s"), "");
  941. X                break;
  942. X            case 'Y':
  943. X                if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
  944. X                    printf(optform("%s"), typename[0]);
  945. X                else if ((statbuf.st_mode & S_IFMT) == S_IFBLK)
  946. X                    printf(optform("%s"), typename[1]);
  947. X                else if ((statbuf.st_mode & S_IFMT) == S_IFCHR)
  948. X                    printf(optform("%s"), typename[2]);
  949. X#ifdef S_IFLNK
  950. X                else if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
  951. X                    printf(optform("%s"), typename[3]);
  952. X#endif
  953. X#ifdef S_IFIFO
  954. X                else if ((statbuf.st_mode & S_IFMT) == S_IFIFO)
  955. X                    printf(optform("%s"), typename[4]);
  956. X#endif
  957. X#ifdef S_IFSOCK
  958. X                else if ((statbuf.st_mode & S_IFMT) == S_IFSOCK)
  959. X                    printf(optform("%s"), typename[5]);
  960. X#endif
  961. X                else if ((statbuf.st_mode & S_IFMT) == S_IFREG)
  962. X                    printf(optform("%s"), typename[6]);
  963. X                else
  964. X                    printf(optform("%s"), "");
  965. X                break;
  966. X            case 'q':
  967. X                for (i = 0400; i; i >>= 1)
  968. X                    if (statbuf.st_mode & i)
  969. X                        printf(optform("%s"), "1");
  970. X                    else
  971. X                        printf(optform("%s"), "0");
  972. X                break;
  973. X            case 'Q':
  974. X#ifdef S_IFLNK
  975. X                if ((statbuf.st_mode & S_IFMT) == S_IFLNK && ! lflag)
  976. X                    break;
  977. X#endif
  978. X                if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
  979. X                    j = 12;
  980. X                else
  981. X                    j = 0;
  982. X                for (i = 04000; i; i >>= 1, j++)
  983. X                    if (statbuf.st_mode & i)
  984. X                        printf(optform("%s"), modename[j]);
  985. X                break;
  986. X#ifdef S_IFLNK
  987. X            case 'L':
  988. X                if ((statbuf.st_mode & S_IFMT) == S_IFLNK) {
  989. X                    int len;
  990. X                    char buf[MAXPATHLEN];
  991. X
  992. X                    if ((len = readlink(inname, buf, MAXPATHLEN)) == -1) {
  993. X                        error("can't readlink `%s'", inname);
  994. X                        break;
  995. X                    }
  996. X                    buf[len] = 0;
  997. X                    printf(optform("%s"), buf);
  998. X                    Lprinted = 1;
  999. X                } else 
  1000. X                    printf(optform("%s"), "");
  1001. X                break;
  1002. X            case '-':
  1003. X                if ((statbuf.st_mode & S_IFMT) == S_IFLNK) {
  1004. X                    fputs(" -> ", stdout);
  1005. X                    Lprinted = 1;
  1006. X                }
  1007. X                break;
  1008. X#endif
  1009. X            default :
  1010. X                putchar(c);
  1011. X                break;
  1012. X            }
  1013. X        }
  1014. X    }
  1015. X    putchar('\n');
  1016. X}
  1017. X
  1018. X/*
  1019. X * error - report trouble
  1020. X */
  1021. Xstatic void                /* does not return */
  1022. Xerror(s1, s2)
  1023. X    char *s1, *s2;
  1024. X{
  1025. X    extern int sys_nerr, errno;
  1026. X    extern char *sys_errlist[];
  1027. X
  1028. X    fprintf(stderr, "%s: ", progname);
  1029. X    fprintf(stderr, s1, s2);
  1030. X    if( errno && errno <= sys_nerr )
  1031. X        fprintf(stderr, " (%s)", sys_errlist[errno]);
  1032. X    putc('\n', stderr);
  1033. X    if (eflag)
  1034. X        exit(1);
  1035. X}
  1036. X
  1037. X/*
  1038. X * mkprogname - convert string to a meaningful program name
  1039. X * May change the string
  1040. X */
  1041. Xchar *
  1042. Xmkprogname(s)
  1043. X    char *s;
  1044. X{
  1045. X    char *p, *p2;
  1046. X    char *unkown="[unkown]";
  1047. X
  1048. X    if (!s || !*s)
  1049. X        return unkown;
  1050. X    p = s;
  1051. X    if ((p2 = strrchr(s, '/')) > p)        /* Check for path */
  1052. X        p = p2+1;
  1053. X#ifdef MSDOS
  1054. X    if ((p2 = strrchr(s, '\\')) > p)    /* Check for backslash path */
  1055. X        p = p2+1;
  1056. X    if ((p2 = strrchr(s, ':')) > p)        /* Check for drive spec */
  1057. X        p = p2+1;
  1058. X    if ((p2 = strrchr(s, '.')) > p)        /* Check for extension */
  1059. X        *p2=0;
  1060. X    for (p2=p; *p2; p2++)            /* Make it lowercase */
  1061. X        if (isascii(*p2) && isupper(*p2))
  1062. X            *p2 = tolower(*p2);
  1063. X#endif
  1064. X    if (*p)
  1065. X        return p;
  1066. X    else
  1067. X        return unkown;
  1068. X}
  1069. X
  1070. Xchar *modename[] = {                /* File mode english names */
  1071. X    "run with id of the owner ",
  1072. X    "run with id of the group ",
  1073. X    "stay in swap space on termination ",
  1074. X    "owner can read ",
  1075. X    "owner can change ",
  1076. X    "owner can execute ",
  1077. X    "group can read ",
  1078. X    "group can change ",
  1079. X    "group can execute ",
  1080. X    "anyone can read ",
  1081. X    "anyone can change ",
  1082. X    "anyone can execute ",
  1083. X    "",
  1084. X    "files inherit group ",
  1085. X    "only owners can delete files ",
  1086. X    "owner can read ",
  1087. X    "owner can change ",
  1088. X    "owner can access ",
  1089. X    "group can read ",
  1090. X    "group can change ",
  1091. X    "group can access ",
  1092. X    "anyone can read ",
  1093. X    "anyone can change ",
  1094. X    "anyone can access ",
  1095. X};
  1096. X
  1097. X/* File type english names */
  1098. Xchar *typename[] = {
  1099. X    "Directory",
  1100. X    "Block special",
  1101. X    "Character special",
  1102. X    "Symbolic link",
  1103. X    "Named pipe",
  1104. X    "Socket",
  1105. X    "Regular file",
  1106. X};
  1107. X
  1108. X/*
  1109. X * Convert a separator terminated list of strings starting with the
  1110. X * terminator to an array.  The strings should be exactly number else
  1111. X * an error is printed.
  1112. X */
  1113. Xstatic void
  1114. Xparsenames(names, array, number, errname)
  1115. X    char *names, *errname;
  1116. X    char *array[];
  1117. X    int number;
  1118. X{
  1119. X    char term = *names;
  1120. X    char *p, *p2;
  1121. X    int count = 0;
  1122. X
  1123. X    for (p = p2 = names + 1; *p ; p++)
  1124. X        if (*p == term) {
  1125. X            array[count++] = p2;
  1126. X            *p++ = 0;
  1127. X            p2 = p;
  1128. X            if (count > number)
  1129. X                break;
  1130. X        }
  1131. X    if (count != number) {
  1132. X        fprintf(stderr, "%s: expected %d arguments to specify file %s, got %d\n", progname, number, errname, count);
  1133. X        exit(1);
  1134. X    }
  1135. X}
  1136. SHAR_EOF
  1137. if test 14832 -ne "`wc -c < 'stat.c'`"
  1138. then
  1139.     echo shar: error transmitting "'stat.c'" '(should have been 14832 characters)'
  1140. fi
  1141. fi # end of overwriting check
  1142. #    End of shell archive
  1143. exit 0
  1144. --
  1145. Diomidis Spinellis                  Internet:                 dds@cc.ic.ac.uk
  1146. Department of Computing             UUCP:                    ...!ukc!iccc!dds
  1147. Imperial College                    JANET:                    dds@uk.ac.ic.cc
  1148. London SW7 2BZ                      #include "/dev/tty"
  1149.